﻿using System;
using System.Linq;
using System.Threading.Tasks;
using AuctionServer.Domain;
using System.Collections.Generic;
using System.Collections.Concurrent;

namespace AuctionServer
{
    internal sealed class Despatcher
    {
        public static readonly Despatcher Instance = new Despatcher();

        private readonly ConcurrentDictionary<long, UserInfo> users;//= new ConcurrentDictionary<long, UserInfo>();
        private readonly ConcurrentDictionary<long, AuctionInfo> auctions;// = new ConcurrentDictionary<long, AuctionInfo>();

        private Despatcher()
        {
            users = new ConcurrentDictionary<long, UserInfo>();
            auctions = new ConcurrentDictionary<long, AuctionInfo>();
        }

        #region

        public UserInfo GetUser(long userId)
        {
            return users.GetOrAdd(userId, BidService.Instance.GetUserInfo);
        }

        public AuctionInfo GetAuction(long auctionId)
        {
            return auctions.GetOrAdd(auctionId, BidService.Instance.GetAuctionInfo(auctionId));
        }

        public SkResult<Bidding> UpdateInfo(UserInfo user, AuctionInfo auction, string ip)
        {
            var dateTime = DateTime.Now;
            var result = new SkResult<Bidding>(true, string.Empty, null);

            var auctionMoney = user.AuctionMoney - auction.PerPrice;
            var newUser = users[user.Id];
            newUser.AuctionMoney = auctionMoney;
            var newAuction = auctions[auction.Id];
            //if(auction.b)
            var price = auction.CurrentPrice + 0.01M;

            var second = auction.Interval;
            var expectedTime = dateTime.AddSeconds(second);

            newAuction.CurrentPrice = price;
            newAuction.CurrentUserId = user.Id;
            newAuction.CurrentNickName = user.NickName;
            newAuction.ExpectedTime = expectedTime;

            if (users.TryUpdate(user.Id, newUser, user) && auctions.TryUpdate(auction.Id, newAuction, auction))
            {
                var bidding = new Bidding();
                bidding.Price = newAuction.PerPrice;
                bidding.AuctionId = newAuction.Id;
                bidding.CurrentPrice = newAuction.CurrentPrice;
                bidding.UserId = newAuction.CurrentUserId;
                bidding.NickName = newAuction.CurrentNickName;
                bidding.CreatedIp = ip;
                bidding.CreatedBy = newUser.Name;
                bidding.CreatedOn = dateTime;

                Task.Factory.StartNew(()=>BidService.Instance.Bid(bidding, expectedTime));

                result.Status = true;
                result.Data = bidding;
            }
            return result;
        }
        
        public IDictionary<long, bool> GetDealtOrStopAuction()
        {
            var list = new Dictionary<long, bool>();
            var time = DateTime.Now;
            var currentAuctions = GetCurrentAuctions();
            foreach (var auction in currentAuctions)
            {
                if (auction.StartDateTime < time && time < auction.StopDateTime)
                {
                    if (time >= auction.ExpectedTime)
                    {
                        auctions[auction.Id].ActualTime = time;
                        auctions[auction.Id].Status = AuctionStatus.Dealt;
                        list.Add(auction.Id, true);
                    }
                }
                else if (time > auction.StopDateTime)
                {
                    auctions[auction.Id].Status = AuctionStatus.Stop;
                    list.Add(auction.Id, false);
                }
            }
            return list;
        }
        public IList<AuctionInfo> GetCurrentAuctions()
        {
            return auctions.Values.ToList();
        }
        #endregion

        #region
        public void Update()
        {

        }
        public void Load()
        {
            var a = new List<UserInfo>() { new UserInfo { Id = 1, Name = "test", NickName = "test", AuctionMoney = 500 }, new UserInfo { Id = 8, Name = "test2", NickName = "test2", AuctionMoney = 500 } };

            a.ForEach(o => users.TryAdd(o.Id, o));

            var b = BidService.Instance.GetAuctionInfo().ToList();

            b.ForEach(o => auctions.TryAdd(o.Id, o));
        }

        #endregion
    }
}